package circuitbreaker

import (
	"log"
	"sync"
	"sync/atomic"
	"time"

	"go-gateworker/internal/config"
)

// CircuitState 熔断器状态
type CircuitState int

const (
	StateClosed   CircuitState = iota // 关闭状态（正常工作）
	StateOpen                         // 开启状态（熔断）
	StateHalfOpen                     // 半开状态（试探）
)

// CircuitBreaker 熔断器
type CircuitBreaker struct {
	// 配置
	errorThreshold      float64       // 错误阈值百分比
	minimumRequests     int           // 最小请求数
	breakDuration       time.Duration // 熔断持续时间
	halfOpenMaxRequests int           // 半开状态最大请求数

	// 状态
	state           CircuitState // 当前状态
	totalRequests   int64        // 总请求数
	failedRequests  int64        // 失败请求数
	lastStateChange time.Time    // 上次状态变更时间
	halfOpenCount   int32        // 半开状态请求计数

	// 并发控制
	mu sync.RWMutex
}

// New 创建新的熔断器
func New(cfg config.CircuitBreakerConfig) *CircuitBreaker {
	return &CircuitBreaker{
		errorThreshold:      cfg.ErrorThreshold,
		minimumRequests:     cfg.MinimumRequests,
		breakDuration:       cfg.GetBreakDuration(),
		halfOpenMaxRequests: cfg.HalfOpenMaxRequests,
		state:               StateClosed,
		lastStateChange:     time.Now(),
	}
}

// UpdateConfig 更新熔断器配置
func (cb *CircuitBreaker) UpdateConfig(cfg config.CircuitBreakerConfig) {
	cb.mu.Lock()
	defer cb.mu.Unlock()

	cb.errorThreshold = cfg.ErrorThreshold
	cb.minimumRequests = cfg.MinimumRequests
	cb.breakDuration = cfg.GetBreakDuration()
	cb.halfOpenMaxRequests = cfg.HalfOpenMaxRequests

	log.Printf("[INFO] 熔断器配置已更新: 错误阈值=%.1f%%, 最小请求数=%d, 熔断持续时间=%v",
		cb.errorThreshold, cb.minimumRequests, cb.breakDuration)
}

// BeforeRequest 请求前检查熔断状态
func (cb *CircuitBreaker) BeforeRequest() bool {
	cb.mu.RLock()
	defer cb.mu.RUnlock()

	now := time.Now()

	switch cb.state {
	case StateClosed:
		return true // 关闭状态允许所有请求

	case StateOpen:
		// 检查是否可以切换到半开状态
		if now.Sub(cb.lastStateChange) >= cb.breakDuration {
			cb.transitionToHalfOpen()
			// 允许一个请求通过
			return cb.allowHalfOpenRequest()
		}
		return false // 熔断状态，拒绝请求

	case StateHalfOpen:
		// 半开状态限制请求数量
		return cb.allowHalfOpenRequest()

	default:
		return true
	}
}

// AfterRequest 请求后更新熔断状态
func (cb *CircuitBreaker) AfterRequest(success bool) {
	// 增加计数器
	atomic.AddInt64(&cb.totalRequests, 1)

	if !success {
		atomic.AddInt64(&cb.failedRequests, 1)
	}

	cb.mu.Lock()
	defer cb.mu.Unlock()

	// 特殊处理半开状态
	if cb.state == StateHalfOpen {
		if !success {
			// 半开状态失败，立即重新熔断
			log.Printf("[WARN] 半开状态请求失败，重新熔断")
			cb.transitionToOpen()
			return
		}

		// 半开状态请求成功，检查是否可以关闭熔断
		halfOpenCount := atomic.LoadInt32(&cb.halfOpenCount)
		if int(halfOpenCount) >= cb.halfOpenMaxRequests {
			// 半开状态通过了足够的请求，关闭熔断
			log.Printf("[INFO] 半开状态成功通过 %d 个请求，关闭熔断", halfOpenCount)
			cb.transitionToClosed()
		}
		return
	}

	// 关闭状态下检查是否需要熔断
	if cb.state == StateClosed {
		totalRequests := atomic.LoadInt64(&cb.totalRequests)
		failedRequests := atomic.LoadInt64(&cb.failedRequests)

		// 只有当请求数达到最小阈值才考虑熔断
		if totalRequests >= int64(cb.minimumRequests) {
			errorRate := float64(failedRequests) / float64(totalRequests) * 100.0
			if errorRate >= cb.errorThreshold {
				log.Printf("[WARN] 错误率 %.1f%% 超过阈值 %.1f%%，触发熔断 (请求: %d, 失败: %d)",
					errorRate, cb.errorThreshold, totalRequests, failedRequests)
				cb.transitionToOpen()
			}
		}
	}
}

// Reset 重置熔断器状态
func (cb *CircuitBreaker) Reset() {
	cb.mu.Lock()
	defer cb.mu.Unlock()

	cb.state = StateClosed
	cb.totalRequests = 0
	cb.failedRequests = 0
	cb.lastStateChange = time.Now()
	atomic.StoreInt32(&cb.halfOpenCount, 0)

	log.Printf("[INFO] 熔断器状态已重置为关闭状态")
}

// GetState 获取当前熔断状态
func (cb *CircuitBreaker) GetState() CircuitState {
	cb.mu.RLock()
	defer cb.mu.RUnlock()
	return cb.state
}

// GetStats 获取统计数据
func (cb *CircuitBreaker) GetStats() map[string]interface{} {
	cb.mu.RLock()
	defer cb.mu.RUnlock()

	totalRequests := atomic.LoadInt64(&cb.totalRequests)
	failedRequests := atomic.LoadInt64(&cb.failedRequests)

	var errorRate float64
	if totalRequests > 0 {
		errorRate = float64(failedRequests) / float64(totalRequests) * 100.0
	}

	return map[string]interface{}{
		"state":           cb.stateString(),
		"total_requests":  totalRequests,
		"failed_requests": failedRequests,
		"error_rate":      errorRate,
		"since_change":    time.Since(cb.lastStateChange).String(),
	}
}

// 内部方法 - 转换到开启状态
func (cb *CircuitBreaker) transitionToOpen() {
	cb.state = StateOpen
	cb.lastStateChange = time.Now()
	log.Printf("[WARN] 熔断器切换为开启状态，将持续 %v", cb.breakDuration)
}

// 内部方法 - 转换到半开状态
func (cb *CircuitBreaker) transitionToHalfOpen() {
	cb.state = StateHalfOpen
	cb.lastStateChange = time.Now()
	atomic.StoreInt32(&cb.halfOpenCount, 0)
	log.Printf("[INFO] 熔断器切换为半开状态，将测试 %d 个请求", cb.halfOpenMaxRequests)
}

// 内部方法 - 转换到关闭状态
func (cb *CircuitBreaker) transitionToClosed() {
	cb.state = StateClosed
	cb.lastStateChange = time.Now()
	cb.totalRequests = 0
	cb.failedRequests = 0
	log.Printf("[INFO] 熔断器切换为关闭状态，系统恢复正常")
}

// 内部方法 - 半开状态是否允许请求
func (cb *CircuitBreaker) allowHalfOpenRequest() bool {
	count := atomic.AddInt32(&cb.halfOpenCount, 1)
	return int(count) <= cb.halfOpenMaxRequests
}

// 内部方法 - 获取状态字符串
func (cb *CircuitBreaker) stateString() string {
	switch cb.state {
	case StateClosed:
		return "closed"
	case StateOpen:
		return "open"
	case StateHalfOpen:
		return "half-open"
	default:
		return "unknown"
	}
}
